package com.oromwin.repos.client;

import java.io.File;

import org.apache.commons.logging.Log;

import com.oromwin.repos.common.Logger;
import com.oromwin.repos.common.ReposException;
import com.oromwin.repos.common.Common.ReposResult;
import com.oromwin.repos.data.FileTable;
import com.oromwin.repos.data.MediaTable;
import com.oromwin.repos.data.VolumeTable;
import com.oromwin.repos.socket.request.Request;
import com.oromwin.repos.socket.request.file.CreateFileRequest;
import com.oromwin.repos.socket.request.file.DeleteFileRequest;
import com.oromwin.repos.socket.request.file.ReadFileRequest;
import com.oromwin.repos.socket.request.media.CreateMediaRequest;
import com.oromwin.repos.socket.request.media.DeleteMediaRequest;
import com.oromwin.repos.socket.request.volume.CreateVolumeRequest;
import com.oromwin.repos.socket.request.volume.DeleteVolumeRequest;
import com.oromwin.repos.socket.response.Response;
import com.oromwin.repos.socket.response.file.CreateFileResponse;
import com.oromwin.repos.socket.response.file.DeleteFileResponse;
import com.oromwin.repos.socket.response.file.ReadFileResponse;
import com.oromwin.repos.socket.response.media.CreateMediaResponse;
import com.oromwin.repos.socket.response.media.DeleteMediaResponse;
import com.oromwin.repos.socket.response.volume.CreateVolumeResponse;
import com.oromwin.repos.socket.response.volume.DeleteVolumeResponse;

public class ReposSocketClient extends AbstractSocketClient {
    private Log log = Logger.getLog(ReposSocketClient.class);
    private Request _req = null;
    private Response _res = null;

    public ReposSocketClient() {
    }
    
    public boolean createVolume(String volumeName) {
        if (log.isDebugEnabled()) log.debug(String.format("createVolume, volumeName {%s}", volumeName));
        try {
            connect();
            _req = (Request) new CreateVolumeRequest(volumeName);
            _req.send(getDataOutputStream());
            _res = (Response) new CreateVolumeResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("createVolume, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success)
                return true;
        } catch (ReposException e) {
            String message = String.format("Failed to create volume, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        }
        return false;
    }
    
    public boolean deleteVolume(String volumeName) {
        return deleteVolume(volumeName, false);
    }
    
    public boolean deleteVolume(String volumeName, boolean force) {
        if (log.isDebugEnabled()) log.debug(String.format("deleteVolume, {%s}", volumeName));
        try {
            connect();
            _req = (Request) new DeleteVolumeRequest(volumeName, force);
            _req.send(getDataOutputStream());
            _res = (Response) new DeleteVolumeResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("deleteVolume, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success)
                return true;
        } catch (ReposException e) {
            String message = String.format("Failed to delete volume, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        }
        return false;
    }
    
    public VolumeTable readVolume(String volumeName) {
        return null;
    }
    
    public boolean createMedia(String volumeName, File mediaPath, Long mediaMaxBytes) {
        if (log.isDebugEnabled()) log.debug(String.format("createMedia, volumeName:mediaPath:mediaMaxBytes {%s:%s:%d}", volumeName, mediaPath, mediaMaxBytes));
        try {
            connect();
            _req = (Request) new CreateMediaRequest(volumeName, mediaPath, mediaMaxBytes);
            _req.send(getDataOutputStream());
            _res = (Response) new CreateMediaResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("createMedia, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success)
                return true;
        } catch (ReposException e) {
            String message = String.format("Failed to create media, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        }
        return false;
    }
    
    public boolean deleteMedia(String volumeName, File mediaPath) {
        return deleteMedia(volumeName, mediaPath, false);
    }
    
    public boolean deleteMedia(String volumeName, File mediaPath, boolean force) {
        if (log.isDebugEnabled()) log.debug(String.format("deleteMedia, volumeName:mediaPath {%s:%s}", volumeName, mediaPath));
        try {
            connect();
            _req = (Request) new DeleteMediaRequest(volumeName, mediaPath, force);
            _req.send(getDataOutputStream());
            _res = (Response) new DeleteMediaResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("deleteMedia, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success)
                return true;
        } catch (ReposException e) {
            String message = String.format("Failed to delete media, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        }
        return false;
    }
    
    public MediaTable readMedia(String volumeName, File mediaPath) {
        return null;
    }
    
    public String createFile(String volumeName, File filePath) {
        if (log.isDebugEnabled()) log.debug(String.format("createFile, volumeName:filePath {%s:%s}", volumeName, filePath));
        String fileId = null;
        try {
            connect();
            _req = (Request) new CreateFileRequest(volumeName, filePath);
            _req.send(getDataOutputStream());
            _res = (Response) new CreateFileResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("createFile, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success) {
                if (_res instanceof CreateFileResponse) {
                    CreateFileResponse res = (CreateFileResponse) _res;
                    fileId = res.getFileId();
                } else {
                    String message = String.format("Illggal response object, class {%s}", _res.getClass().toString());
                    ReposException.create(log, message);
                }
            }
        } catch (ReposException e) {
            String message = String.format("Failed to create file, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        }
        return fileId;
    }
    
    public boolean deleteFile(String volumeName, String fileId) {
        return deleteFile(volumeName, fileId, false);
    }
    
    public boolean deleteFile(String volumeName, String fileId, boolean force) {
        if (log.isDebugEnabled()) log.debug(String.format("deleteFile, volumeName:fileId {%s:%s}", volumeName, fileId));
        try {
            connect();
            _req = (Request) new DeleteFileRequest(volumeName, fileId, force);
            _req.send(getDataOutputStream());
            _res = (Response) new DeleteFileResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("deleteFile, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success)
                return true;
        } catch (ReposException e) {
            String message = String.format("Failed to delete file, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        }
        return false;
    }
    
    public boolean saveFile(String volumeName, String fileId, File localPath) {
        if (log.isDebugEnabled()) log.debug(String.format("readFile, volumeName:fileId {%s:%s}", volumeName, fileId));
        try {
            connect();
            _req = (Request) new ReadFileRequest(volumeName, fileId, localPath);
            _req.send(getDataOutputStream());
            _res = (Response) new ReadFileResponse();
            _res.receive(getDataInputStream());
            disconnect();
            if (log.isDebugEnabled()) log.debug(String.format("readFile, Result {%s}", _res.getResult()));
            if (_res.getResult() == ReposResult.Success) {
                return true;
            }
        } catch (ReposException e) {
            String message = String.format("Failed to read file, cause {%s}", e.getMessage());
            ReposException.create(log, e, message);
        } catch (NullPointerException e) {
            String message = String.format("Destination path is null, path {%s}", localPath);
            ReposException.create(log, e, message);
        } catch (SecurityException e) {
            String message = String.format("Can't access to requested directory, path {%s}", localPath);
            ReposException.create(log, e, message);
        }
        return false;
    }
    
    public FileTable readFile(String volumeName, String fileId) {
        return null;
    }
}
